#ifndef __M_FMT_H__
#define __M_FMT_H__
#include <memory>
#include <ctime>
#include <iostream>
#include <vector>
#include <sstream>
#include <assert.h>
#include "message.hpp"

class FormatItem
{
public:
    using ptr = std::shared_ptr<FormatItem>;
    virtual void format(std::ostream& os, const LogMsg& msg) = 0;
    virtual ~FormatItem(){}
};

// 派生子类--消息、等级、时间、文件名、行号、线程id、日志器名、制表符、换行、其他
class MsgFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << msg._payload;
    }
};

class LevelFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << LogLevel::toString(msg._level);
    }
};

class TimeFormatItem :public FormatItem
{
public:
    // 传入时间戳，需要转换。然后将转换的时间组织成字符串
    TimeFormatItem(const std::string& fmt = "%H:%M%S") :_time_fmt(fmt){}
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        struct tm t;
        localtime_r(&msg._time, &t);
        char tmp[32] = {0};
        strftime(tmp, 31, _time_fmt.c_str(), &t);
        os << tmp;
    }
// 时间有不同的字符串组合格式，这里默认%H:%M:%S
private:
    std::string _time_fmt;
};

class FileFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << msg._file;
    }
};

class LineFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << msg._line;
    }
};

class ThreadFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << msg._tid;
    }
};

class LoggerFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << msg._logger;
    }
};

class TabFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << "\t";
    }
};

class NLineFormatItem :public FormatItem
{
public:
    virtual void format(std::ostream& os, const LogMsg& msg) override
    {
        os << "\n";
    }
};

// abcdef[%d{%H}] 中括号和开始的字母
class OtherFormatItem :public FormatItem
{
public:
    OtherFormatItem(const std::string& str) :_str(str){}
    virtual void format(std::ostream& os, const LogMsg& msg)
    {
        os << _str;
    }
private:
    std::string _str;
};

/*
    %d 日期，子格式{%H:%M:%S}
    %t 线程id
    %c 日志器名称
    %f 源码文件名
    %l 源码行号
    %p 日志级别
    %T 制表符缩进
    %m 主体消息
    %n 换行
*/
class Formatter
{
public:
    using ptr = std::shared_ptr<Formatter>;
    Formatter(const std::string &pattern =
                  "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
        : _pattern(pattern)
    {
        assert(parsePattern());
    }

    // 对msg格式化
    void format(std::ostream& out, const LogMsg& msg)
    {
        for (auto& item : _items)
        {
            item->format(out, msg);
        }
    }

    std::string format(const LogMsg& msg)
    {
        std::stringstream ss;
        format(ss, msg);
        return ss.str();
    }
private:
    // 对格式化规则字符串解析
    bool parsePattern()
    {
        // 1.对格式化规则字符串解析
        // ab%%cde[%d{%H:%M:%S}][%p]%T%m%n
        std::vector<std::pair<std::string, std::string>> fmt_order;
        size_t pos = 0;
        std::string key, val;
        while (pos < _pattern.size())
        {
            // 处理原始字符串，判断是否%，不是就是原始字符
            if (_pattern[pos] != '%')
            {
                val.push_back(_pattern[pos++]);
                continue;
            }

            // 能走下来就是pos位置是%，%%处理为一个原始%字符
            if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
            {
                val.push_back('%');
                pos += 2;
                continue;
            }

            // 能走下来，代表后面是格式化字符，原始字符串处理完毕
            if (val.empty() == false)
            {
                fmt_order.push_back(std::make_pair("", val));
                val.clear();
            }

            // 这时候指向的是%位置，格式化字符串的处理
            pos += 1;  // pos指向格式化字符位置
            if (pos == _pattern.size())
            {
                std::cout << "%之后，没有对应的格式化字符！\n";
                return false;
            }
            key = _pattern[pos];

            // 这时候pos指向格式化字符后的位置
            pos += 1;
            if (pos < _pattern.size() && _pattern[pos] == '{')
            {
                pos += 1;  // 指向子规则的起始位置
                while (pos < _pattern.size() && _pattern[pos] != '}')
                {
                    val.push_back(_pattern[pos++]);
                }
                // 走到末尾跳出循环，代表没有遇到}，格式错误
                if (pos == _pattern.size())
                {
                    std::cout << "子规则{}匹配出错\n";
                    return false; // 没有找到}
                }

                pos += 1;  // 指向}位置，向后走一步，到下次处理的新位置
            }

            fmt_order.push_back(std::make_pair(key, val));
            key.clear();
            val.clear();
        }

        // 2.根据解析得到的数据初始化格式化子项数组成员
        for (auto& it : fmt_order)
        {
            _items.push_back(createItem(it.first, it.second));
        }

        return true;
    }

    // 根据不同格式字符创建不同格式化子项对象
    FormatItem::ptr createItem(const std::string& key, const std::string& val)
    {
        if (key == "d")
            return std::make_shared<TimeFormatItem>(val);
        if (key == "t")
            return std::make_shared<ThreadFormatItem>();
        if (key == "c")
            return std::make_shared<LoggerFormatItem>();
        if (key == "f")
            return std::make_shared<FileFormatItem>();
        if (key == "l")
            return std::make_shared<LineFormatItem>();
        if (key == "p")
            return std::make_shared<LevelFormatItem>();
        if (key == "T")
            return std::make_shared<TabFormatItem>();
        if (key == "m")
            return std::make_shared<MsgFormatItem>();
        if (key == "n")
            return std::make_shared<NLineFormatItem>();
        if (key.empty())
            return std::make_shared<OtherFormatItem>(val);
        std::cout << "没有对应的格式化字符：%" << key << std::endl;
        abort();
        return FormatItem::ptr();
    }

private:
    std::string _pattern;  // 格式化规则字符串
    std::vector<FormatItem::ptr> _items;
};
#endif
